View Javadoc

1   /*
2    * GRIDIdentityMappingServiceExampleImpl.java
3    *
4    * Created on January 5, 2005, 6:00 PM
5    */
6   
7   package org.opensciencegrid.authz.service;
8   
9   import java.util.StringTokenizer;
10  import java.util.ArrayList;
11  import java.util.Enumeration;
12  import java.io.IOException;
13  import java.io.BufferedReader;
14  import java.io.InputStreamReader;
15  import java.io.InputStream;
16  import java.io.FileInputStream;
17  
18  import org.opensciencegrid.authz.common.GridId;
19  import org.opensciencegrid.authz.common.LocalId;
20  
21  import org.apache.log4j.Category;
22  
23  /***
24   * An example simple mapping service implementation that 
25   * maps an incoming request based on
26   * /etc/grid-security/grid-mapfile
27   *
28   * @author G. Carcassi, M. Lorch
29   */
30  
31  
32  
33  public class GRIDIdentityMappingServiceExampleImpl implements GRIDIdentityMappingService {
34  
35      /*** Log4Java logger */
36      static Category log = Category.getInstance(GRIDIdentityMappingServiceExampleImpl.class.getName() );
37  
38      /*** the standard Gridmap file location */
39      private static String STDMAPFILE = "/etc/grid-security/mapsvc-gridmap";
40  
41      /*** the comment chars for the gridmap file */
42      private static final String COMMENT_CHARS = "#";
43  
44      /*** the contents of the gridmap file, parsed at object instantiation */
45      private ArrayList mappings;
46  
47      /*** internal format to hold gridmap entries */
48      private class MapEntry extends LocalId {
49         String subjectDN;
50         String fqan;
51         public void setSubjectDN(String s) {this.subjectDN = s;}
52         public String getSubjectDN() {return this.subjectDN;}
53         public void setFQAN(String f) {this.fqan = f;}
54         public String getFQAN() {return this.fqan;}
55         public String toString() {
56           String r = subjectDN+" "+getUserName()+" "+fqan+" "+getGroupName()+" ";
57           String[] gs = getSupplementalGroupNames();
58           if(gs!=null) {
59             for(int i=0;i<gs.length;i++) 
60               r = r.concat(gs[i]+" ");
61           }
62           return r;
63         }
64      }
65  
66      /*** initialization method parses gridmap file 
67       * gridmap file location may be supplied via system property gridmap.file 
68       */
69      public void init() {
70         String mapfile = System.getProperty("gridmap.file");
71         if(mapfile!=null) 
72            log.debug("Parsing gridmap file from: "+mapfile);
73         else {
74            mapfile=STDMAPFILE;
75            log.debug("System property gridmap.file not available");
76            log.debug("Parsing gridmap file from standard location: "+mapfile);
77         }
78         try {
79            mappings = parseMappingFile(mapfile);
80         } catch (Exception e) {
81            log.error("Unable to parse gridmap file: "+e);
82            log.debug(e);
83         }
84         if(mappings==null || mappings.isEmpty()) log.debug("No gridmap entries were retrieved from gridmap file");
85         else log.debug("Gridmap table loaded: "+mappings);
86      }
87  
88      /*** the main function called from the outside, please note that
89        * this is a test implementation
90        * the host name of the service for which a mapping is being 
91        * requested is not checked, neither is the issuer of the VOMS
92        * attribute (fqan) considered
93        */
94      public LocalId mapCredentials(GridId gridID) {
95          log.debug("entered mapCredentials of mapping service");
96          MapEntry m;
97  
98          if(mappings==null) init(); // try to load mappings the first time around
99  
100         if(mappings==null) {
101            log.debug("mapping table is empty, returning null (deny)");
102            return null;  
103         }
104 
105         log.debug("attempting to find a mapping");
106 
107         for(int i=0;i<mappings.size();i++) {
108           m = (MapEntry) mappings.get(i);
109           log.debug("comparing "+m.getSubjectDN()+" to "+gridID.getUserDN());
110           if (m.getSubjectDN().equals(gridID.getUserDN()) ) {
111             log.debug("found matching subject DN in gridmap table");
112             // are fqan's present, if not we have a match
113             if(m.getFQAN()==null && gridID.getUserFQAN()==null)  {	
114                  log.debug("no FQANS, returning mapping for local user: "+m.getUserName());
115                  return (LocalId) m; 
116             }
117             // if only one present, then continue, no match
118             if(m.getFQAN()==null || gridID.getUserFQAN()==null) {
119                  log.debug("FQANs don't match for this entry (null)");
120                  continue;
121             }
122             // both are present, if they match then return 
123             if(m.getFQAN().equals(gridID.getUserFQAN())) {
124                  log.debug("FQAN matches, returning mapping for local user: "+m.getUserName());
125                  return (LocalId) m;
126             }
127             else {
128                  log.debug("FQANs don't match for this entry");
129             }   
130 
131           } // end if m.getSubject
132 
133         } // end for
134          
135         log.debug("returning null, no valid mapping could be found");
136         return null;
137 
138     } // end mapCredentials
139 
140 
141     /*** file parser function that returns an array of localID objects 
142       * function is tuned for configurations with up to 50 entries
143       * it can parse standard GLOBUS gridmap files as well as gridmap
144       * files that also contain fqan, group, and supplemental group 
145       * fields (in that order)
146       * It DOES NOT support multiple local user names (separated via a comma)
147       */
148     private ArrayList parseMappingFile(String mfile) 
149      throws IOException {
150 
151      InputStream in = null;
152      String line;
153      ArrayList mappings = new ArrayList(50);
154      MapEntry m;
155      QuotedStringTokenizer tokenizer;
156 
157      in = new FileInputStream(mfile);
158      
159      BufferedReader reader =
160             new BufferedReader(new InputStreamReader(in));
161 
162      while( (line = reader.readLine()) != null) {
163         line = line.trim();
164         if ( (line.length() == 0) ||
165                ( line.substring(0, 1).indexOf(COMMENT_CHARS) != -1) ) {
166             continue;
167         }
168         // ok, line is not a comment
169         
170         m = new MapEntry();
171 
172         tokenizer = new QuotedStringTokenizer(line);
173 
174         if (tokenizer.hasMoreTokens()) {
175             m.setSubjectDN(tokenizer.nextToken());
176         } else {
177             throw new IOException("Subject DN not defined: " + line);
178         }
179         if (tokenizer.hasMoreTokens()) {
180             m.setUserName(tokenizer.nextToken());
181         } else {
182             throw new IOException("Local user name not defined: " + line);
183         }
184         if (tokenizer.hasMoreTokens()) { //optional fqan
185             m.setFQAN(tokenizer.nextToken());
186         }
187         if (tokenizer.hasMoreTokens()) { // optional primary group 
188             m.setGroupName(tokenizer.nextToken());
189         }
190         // remainder are supplemental group names 
191         if (tokenizer.hasMoreTokens()) { // optional suppl. group 
192            ArrayList sg = new ArrayList(16); 
193            while(tokenizer.hasMoreTokens() ) {
194               sg.add(tokenizer.nextToken());
195            }
196            if(!sg.isEmpty()) { // we have suppl. groups
197               String [] sglist = new String[sg.size()];
198               for(int i=0;i<sg.size();i++) {
199                 sglist[i]=(String)sg.get(i);
200               }
201               m.setSupplementalGroupNames(sglist);
202            }
203         }
204 
205         // done parsing the file, add the mapentry to our result
206         // at least the userid and the subjectDN must be set (otherwise we threw exception)
207       
208         mappings.add(m);
209 
210      } // end while line reader
211  
212      // close file
213      if (in != null) in.close();
214         
215      return mappings;
216    } // end parseMappingFile
217 
218 
219 } // end class
220 
221 
222 /*
223  * This class was snatched from org.globus.util (old cog kit version)
224  * This class is not thread safe.
225  */
226 
227 class QuotedStringTokenizer implements Enumeration {
228 
229     private int limit;
230     private int start;
231     private String str;
232 
233     public QuotedStringTokenizer(String str) {
234         this.str = str;
235         start = 0;
236         limit = str.length();
237     }
238 
239     public Object nextElement() {
240         return nextToken();
241     }
242 
243    public String nextToken() {
244         while ((start < limit) && (str.charAt(start) <= ' ')) {
245             start++;    // eliminate leading whitespace
246         }
247 
248         if (start == limit) return null;
249 
250         StringBuffer buf = new StringBuffer(limit-start);
251         char ch;
252         char quote = str.charAt(start);
253         if (quote == '"' || quote == '\'') {
254             start++;
255             for (int i=start;i<limit;i++) {
256                 ch = str.charAt(i);
257                 start++;
258                 if (ch == quote) {
259                     break;
260                 } else if (ch == '//') {
261                     buf.append( str.charAt(++i) );
262                     start++;
263                 } else {
264                     buf.append(ch);
265                 }
266             }
267             return buf.toString();
268         } else {
269             for (int i=start;i<limit;i++) {
270                 ch = str.charAt(i);
271                 start++;
272                 if (ch == ' ') {
273                     break;
274                 } else {
275                     buf.append(ch);
276                 }
277             }
278         }
279 
280        return buf.toString();
281     }
282 
283     public boolean hasMoreElements() {
284         return hasMoreTokens();
285     }
286 
287     public boolean hasMoreTokens() {
288         while ((start < limit) && (str.charAt(start) <= ' ')) {
289             start++;    // eliminate leading whitespace
290         }
291 
292         return (start != limit);
293     }
294 
295     public int countTokens() {
296         int localStart = start;
297         int i = 0;
298         while( nextToken() != null ) {
299             i++;
300         }
301         start = localStart;
302         return i;
303     }
304 
305 } // end quotedTokenizer class
306 
307